package com.darker.secking.controller;


import com.darker.secking.config.Accessimit;
import com.darker.secking.entity.*;
import com.darker.secking.exception.GlobalException;
import com.darker.secking.rabbitmq.MQSender;
import com.darker.secking.service.IGoodsService;
import com.darker.secking.service.IOrderService;
import com.darker.secking.service.ISeckingGoodsService;
import com.darker.secking.service.ISeckingOrderService;
import com.darker.secking.utils.JsonUtil;
import com.darker.secking.vo.RespBean;
import com.darker.secking.vo.RespBeanEnum;
import com.wf.captcha.ArithmeticCaptcha;
import com.wf.captcha.SpecCaptcha;
import com.wf.captcha.base.Captcha;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.data.redis.core.script.RedisScript;
import org.springframework.stereotype.Controller;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.*;
import java.io.IOException;
import java.sql.Blob;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Controller
@Slf4j
@RequestMapping("/seckill")
public class SecKillController implements InitializingBean {
    @Autowired
    IGoodsService goodsService;

    @Autowired
    ISeckingOrderService seckingOrderService;

    @Autowired
    ISeckingGoodsService seckingGoodsService;

    @Autowired
    IOrderService orderService;

    @Autowired
    RedisTemplate redisTemplate;

    @Autowired
    RedisScript<Long> redisScript;


    private Map<Long, Boolean> EmptyStockMap = new HashMap<>();

    @Autowired
    MQSender mqSender;

//    @RequestMapping("/doSeckill")
//    public String doScking(Model model, User user, Long goodsId){
//        if(user==null) {
//            return "login";
//        }
//        model.addAttribute("user",user);
//        GoodsVo goods = goodsService.findGoodsById(goodsId);
//        //判断该商品库存是否足够
//        if(goods.getStockCount()<1){
//            model.addAttribute("errmsg", RespBeanEnum.EMPTY_STOCK.getMessage());
//            return "secKillFail";
//        }
////        查询订单表中是否有该用户的数据
//       SeckingOrder seckingOrder= seckingOrderService.getSeckingOrderById(user.getId());
////        如果有则返回重复秒杀的信息
//        if(seckingOrder!=null){
//            model.addAttribute("errmsg",RespBeanEnum.REPEATE_ERROR.getMessage());
//            return "secKillFail";
//        }
//           Order order= orderService.secking(user,goods);
//            model.addAttribute("order",order);
//            model.addAttribute("goods",goods);
//            return "orderDetail";
//    }

    @PostMapping(value = "/{path}/doSeckill", produces = "application/json;charset=utf-8")
    @ResponseBody
    public RespBean doSecking(@PathVariable String path, User user, Long goodsId) {
        if (user == null) {
            return RespBean.error(RespBeanEnum.LOGIN_ERROR);
        }
        ValueOperations valueOperations = redisTemplate.opsForValue();
        Boolean checkPath = orderService.checkPath(user, goodsId, path);
        if (!checkPath) {
            return RespBean.error(RespBeanEnum.PATH_ERROR);
        }

        //查询Redis中订单是否已经存在 存在则是重复秒杀 直接返回错误信息
        SeckingOrder seckingOrder = (SeckingOrder) valueOperations.get("order:" + user.getId() + ":" + goodsId);
        if (seckingOrder != null) {
            return RespBean.error(RespBeanEnum.REPEATE_ERROR);
        }

        //内存标记 减少redis访问
        if (EmptyStockMap.get(goodsId)) {
            return RespBean.error(RespBeanEnum.EMPTY_STOCK);
        }
        //对redis中Key:"seckillGoods:"+goodsId 的值进行递减  也就是对库存递减
//        Long seckingCount = valueOperations.decrement("seckillGoods:" + goodsId);
//        当库存小于0时则返回错误信息
        //通过lua脚本进行煎
        Long seckingCount = (Long) redisTemplate.execute(redisScript, Collections.singletonList("seckillGoods:" + goodsId), Collections.EMPTY_LIST);
        if (seckingCount < 0) {
            //当进入这条语句时，这时的redis的库存数量为-1  需要手动加1使数据为0方便查看
            EmptyStockMap.put(goodsId, true);

//            valueOperations.increment("seckillGoods:" + goodsId);
            return RespBean.error(RespBeanEnum.EMPTY_STOCK);
        }
        //创建RabbitMQ需要处理的对象
        SeckillMessage seckillMessage = new SeckillMessage(user, goodsId);
        //将对象序列化成JSON字符串
        String seckillMessageJSON = JsonUtil.object2JsonStr(seckillMessage);
        //发送RabbitMQ消息   进行异步创建订单信息
        mqSender.sckillGoods(seckillMessageJSON);

        return RespBean.success(0);

//        GoodsVo goods = goodsService.findGoodsById(goodsId);
//        //判断该商品库存是否足够
//        if(goods.getStockCount()<0){
//           return RespBean.error(RespBeanEnum.EMPTY_STOCK);
//        }
////        查询订单表中是否有该用户的数据
//        SeckingOrder seckingOrder= (SeckingOrder) redisTemplate.opsForValue().get("order:"+user.getId()+":"+goods.getId());
//
////        如果有则返回重复秒杀的信息
//        if(seckingOrder!=null){
//         return RespBean.error(RespBeanEnum.REPEATE_ERROR);
//        }

    }

    @GetMapping(value = "/path")
    @ResponseBody
    @Accessimit(second=5,maxCount=5,needLogin=true)
    public RespBean getPath(User user, Long goodsId,String captcha) {
        if (user == null) {
            return RespBean.error(RespBeanEnum.LOGIN_ERROR);
        }

        boolean check=orderService.checkCaptcha(user,goodsId,captcha);
        if(!check){
            return RespBean.error(RespBeanEnum.REQUEST_ERROR);
        }
        String url = orderService.createPath(user, goodsId);
        return RespBean.success(url);
    }

    //成功->orderId， 失败->-1  ,排队中->0
    @GetMapping(value = "/result", produces = "application/json;charset=utf-8")
    @ResponseBody
    public RespBean getResult(User user, Long goodsId) {
        if (user == null) {
            return RespBean.error(RespBeanEnum.LOGIN_ERROR);
        }
        Long orderId = seckingOrderService.getResult(user, goodsId);
        return RespBean.success(orderId);
    }

    @GetMapping(value = "/captcha")
    public void verifyCode(User user, Long goodsId, HttpServletResponse response) {
        if (null == user || goodsId < 0) {
            throw new GlobalException(RespBeanEnum.REQUEST_ILLEGAL);
        }
        response.setContentType("image/gif");
        response.setHeader("Pragma", "No-cache");
        response.setHeader("Cache-Control", "no-cache");
        response.setDateHeader("Expires", 0);

        ArithmeticCaptcha captcha = new ArithmeticCaptcha(130, 32, 3);

        redisTemplate.opsForValue().set("captcha:" + user.getId() + ":" + goodsId, captcha.text(), 300, TimeUnit.SECONDS);
        try {
            captcha.out(response.getOutputStream());
        } catch (IOException e) {
            log.error("验证码生成失败", e.getMessage());
        }
    }

    //项目启动时执行
    @Override
    public void afterPropertiesSet() throws Exception {
        //初始化时把秒杀商品的信息存入redis中
        List<SeckingGoods> seckingGoodsList = seckingGoodsService.list();
        if (CollectionUtils.isEmpty(seckingGoodsList)) {
            return;
        }
        seckingGoodsList.forEach(seckingGoods -> {
                    redisTemplate.opsForValue().set("seckillGoods:" + seckingGoods.getGoodsId()
                            , seckingGoods.getStockCount());
                    EmptyStockMap.put(seckingGoods.getGoodsId(), false);
                }

        );
    }
}
